home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d26 / typefast.arc / TYPEFAST.C < prev    next >
Text File  |  1989-11-27  |  14KB  |  493 lines

  1. /*
  2.  *  TYPEFAST
  3.  *  Improve your typing the fun way
  4.  *    by Steve Spearman   druco!spear  11/18/86
  5.  */
  6.  
  7. /* Fixes/Enhancements:
  8.  *    by Dave Tutelman  att!mtunb!dmt  2/5/89
  9.  *       - Ported to MSDOS PCs (Turbo C & PCcurses).
  10.  *        Compile with #define MSDOS.
  11.  *       - Compile with #define WORDLIST, to use your own favorite words
  12.  *        (in WORDLIST.H), instead of those built into WORDS.C.
  13.  *       - Slowed down missiles so they stay visible @ >9600 baud.
  14.  *       - Fudged highrow to allow more time for longer words.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <curses.h>
  19.  
  20. /* non-int external functions used */
  21. extern long time();
  22.  
  23. /*Declarations follow for non-int functions */
  24. extern void screeninit(),getsetup(),checkhit(),showscore(),cleartarget();
  25.  
  26. #define MAXLEN        20    /*MAX word length */
  27. #define MAXSIZE        30    /*MAX word length + some fudge */
  28. #define    MAXTARGET    10    /*MAX target words*/
  29. #define    MAXMISS        10    /*Number of missed words to end game */
  30. #define MAXROW        23    /*Maximum row allowed */
  31.  
  32. #define    boolean    int    
  33.  
  34. extern char    *words[];    /* word list from other file */
  35. extern int    initwords();    /* word list initializer from other file */
  36.  
  37. struct word {            /* the structure of each word on the screen*/
  38.     char text[MAXLEN];    /* word text */
  39.     int row;        /* screen row position */
  40.     int col;        /* screen column position */
  41.     int len;        /* length of word */
  42.     boolean active;        /* indicates if word is active or not */
  43. };
  44. struct word target[MAXTARGET];
  45.  
  46. /* the following are set in the 'getsetup' function */
  47. int addtarget,    /* Add a new target every x hits*/
  48.     movedown,    /* move top row down every x hits */
  49.     movebottom,    /* move botom row down every x hits */
  50.     startwords;    /* Starting number of target words*/
  51. int lowrow;    /* lowest row number for a word */
  52. int highrow;    /* highest row number for a word */
  53.  
  54. /* internal variables */
  55. int maxword;        /* number of words in list */
  56. int targets=0;        /* total active targets */
  57. int missed=0;        /* total misses */
  58. int total=0;        /* total hits */
  59. long strokes=0;        /* total key stroke hits on words gotten*/
  60. long allstrokes=0;    /* total key stroke hits including bad*/
  61. long starttime;        /* time we started typing */
  62.  
  63. main(argc, argv)
  64. int argc;
  65. char *argv[];
  66. {
  67.         extern char *optarg;
  68.     int      c;
  69.     if (argc > 1) {
  70.         printf("Usage: %s \n", argv[0]);
  71.             exit(1);
  72.           }
  73.  
  74.     initialize();        /* initialize curses */
  75.     getsetup();        /* set difficulty variables */
  76.     screeninit();        /* put up initial display */
  77.     maxword = initwords();    /* get the word list */
  78.  
  79.     for (targets=0;targets < startwords; targets++) {
  80.         newtarget(targets);    /* set up a target word */
  81.     }
  82.     starttime = time ((long *) 0);
  83.  
  84.     while (missed < MAXMISS) {
  85.  
  86.         targetmove();
  87.         refresh();
  88.         napms(600);    /* suspend for so many milliseconds */
  89.         while ((c=getch()) >= 0) {
  90.             if (c == '\033') {    /* ESCAPE */
  91.                 doend();    /* end the game with states*/
  92.             }
  93.             checkhit(c);
  94.         }
  95.           
  96.     }
  97.     move(21,0);
  98.     clrtoeol();
  99.     mvprintw(21,0,"END of Game: you missed the maximum %d words",missed);
  100.     doend();
  101. }
  102.  
  103. /* DOEND
  104.  *
  105.  * Print out the ending statistics and exit gracefully
  106.  */
  107. int 
  108. doend()
  109. {
  110.     mvprintw(22,0,"WPM on words typed correctly: %d",wpm(strokes));
  111.     printw("     WPM on all words typed: %d",wpm(allstrokes));
  112.     goodbye();
  113. }
  114.  
  115. /* TARGETMOVE
  116.  *
  117.  * Moves all targets down a row and checks for any that have reached
  118.  * the bottom.  If they have, it is counted and a new word is created.
  119.  */
  120. int
  121. targetmove()
  122. {
  123. register int num;
  124. for (num = 0; num < MAXTARGET; num++) {
  125.     if ( ! target[num].active)
  126.         continue;
  127.     if (movetarget(num)) {
  128.         newtarget(num);
  129.         missed++;
  130.         flash();
  131.         showscore();
  132.     }
  133. }
  134. }
  135.  
  136. /* CLEARWORD
  137.  *
  138.  * This function clears out the screen position of the word
  139.  * whose structure index is passed.
  140.  */
  141. void
  142. clearword(num)
  143. int num;
  144. {
  145. register int i;
  146.     move(target[num].row,target[num].col);
  147.     for (i=0; i < target[num].len; i++) {
  148.         addch(' ');
  149.     }
  150. }
  151.  
  152. /* MOVETARGET
  153.  *
  154.  * This move the word structure whose index is passed down one row.
  155.  * If this move brings it to the edge of the screen, 1 is returned,
  156.  * otherwise, 0 is returned.
  157.  */
  158. int
  159. movetarget(num)
  160. int num;
  161. {
  162.     clearword(num);        /* clear the old word on screen */
  163.     target[num].row++;    /* move down a row */
  164.     if(target[num].row >= MAXROW)
  165.         return(1);
  166.     mvprintw(target[num].row,target[num].col,target[num].text);
  167.     return(0);
  168. }
  169.  
  170.  
  171. /* NEWTARGET
  172.  *
  173.  * This function produces a new word structure in the structure whose
  174.  * index is passed.   The word is chosen randomly and is placed randomly
  175.  * subject to constraints of screen placement and word proximity.
  176.  */
  177. int
  178. newtarget(num)
  179. int num;
  180. {
  181. register int i;
  182. int    wordno;
  183. boolean    bad;
  184. int    safety;
  185. int    samecol;
  186. int    _highrow;    /* "Fudged" value of highrow for this word. We
  187.              * "give the typist a break" by one row for each
  188.              * "nominal" word of 5 characters in the word. */
  189.  
  190.         wordno = (rand() % maxword);        /* pick a word number */
  191.     strcpy(target[num].text,words[wordno]);    /* copy the word into struct */
  192.     target[num].len=strlen(target[num].text);    /* calculate length */
  193.     _highrow = highrow - target[num].len % 5;    /* fudge _highrow */
  194.     bad = 1;    /* flag that is cleared when we get a good word */
  195.     safety = 0;
  196.     while (bad) {
  197.         if (++safety > 5000)
  198.             error("New word not placable");
  199.         /* try to get a good row and column */
  200.         target[num].row= (rand() % (_highrow - lowrow + 1)) + lowrow;
  201.         target[num].col= (rand() % (80-target[num].len));
  202.         bad = 0;
  203.         /* check all other words to make sure no overlaps */
  204.         for (i=0; i< MAXTARGET; i++) {
  205.             if ( (! target[i].active) || (i == num) )
  206.                 continue;    /* don't check against self */
  207.             samecol = 0;
  208.             if ( (target[num].col <= target[i].col) &&
  209.              ((target[num].col + target[num].len + 1) >= target[i].col))
  210.                 samecol = 1;    /* columns touch/overlap */
  211.             if ( (target[i].col <= target[num].col) &&
  212.               ((target[i].col + target[i].len + 1) >= target[num].col))
  213.                 samecol = 1;    /* columns touch/overlap */
  214.             /* if columns overlap, check that the rows are */
  215.             /* separated by at least one blank to avoid problems */
  216.             /* with erasing or overwriting the other word during */
  217.             /* movement */
  218.             if ( samecol && 
  219.               (abs(target[num].row - target[i].row) < 2)) {
  220.                 bad = 1;    
  221.                 break;
  222.             }
  223.         }
  224.     }
  225.     target[num].active = 1;
  226. }
  227.  
  228. /* CHECKHIT
  229.  *
  230.  * This routine is passed a char each time one is typed.  It collects
  231.  * words and compares the word typed with all words on the screen.  If
  232.  * a match is found, the match lowest on the screen is considered hit
  233.  * and the routine gotit() is called to handle the hit.
  234.  */
  235. void
  236. checkhit(c)
  237. char c;
  238. {
  239. static int count = 0;        /* character counter */
  240. static char line[MAXSIZE];    /* the line you are typing */
  241. int couldhit[MAXTARGET];    /* some booleans */
  242. register int num;
  243. register int row;        /* holds row of number we shot */
  244. int shot;            /* holds the number of word we shot */
  245. /* check for a word separator to end the word */
  246. if ( (c != ' ') && (c != '\n') && ( c != '\r')) {
  247.     allstrokes++;    /* count all key strokes */
  248.     /* character is not a separator, so just collect it */
  249.     if (count >= (MAXSIZE - 2))    /* if line too long, */
  250.         return;    /* wait for next separator to begin again */
  251.     line[count++] = c;
  252.     return;
  253. }
  254. /* if we got here, we got a separator and have a word */
  255. if ( count == 0 )    /* null word */
  256.     return;
  257. line[count] = '\0';
  258. count = 0;    /*reset for next word */
  259. shot = -1;
  260. row = 0;    /* keep track of largest row of word shot */
  261. for (num=0;num < MAXTARGET; num++) {
  262.     if ( ! target[num].active )    /* only check active words */
  263.         continue;
  264.     /* check to see if the word matches */
  265.     if (strncmp(target[num].text,line,MAXSIZE) == 0) {
  266.             /* got a word! */
  267.             /* check if this is lower on screen than any others*/
  268.             if (target[num].row > row) {
  269.                 row = target[num].row;
  270.                 shot = num;
  271.             }
  272.     } 
  273. }
  274. if ( shot == -1 )
  275.     return;
  276. gotit(shot);    /* handle the word we shot */
  277. }
  278.  
  279. /* GOTIT
  280.  *
  281.  * We have gotten the word whose number is passed.  Now produce any
  282.  * appropriate effects and clear out the word.  Also, update score
  283.  * and create a new replacement word.
  284.  */
  285. int 
  286. gotit(num)
  287. int num;
  288. {
  289. register int i,x,y;
  290. char oldc = '\0';
  291. char missile =
  292. #ifdef MSDOS
  293.         0xEA;        /* OMEGA looks like missile on PC screen */
  294. #else
  295.         '^';
  296. #endif
  297.  
  298. int incmove;
  299.     total++;            /* keep track of words gotten */
  300.     x = target[num].col + (target[num].len / 2);    /* center of word */
  301.     y = target[num].row;        /* row of word */
  302.     strokes += target[num].len;    /* count letters */
  303.     incmove = 1;
  304.     if (baudrate() < 9600)
  305.         incmove = 2;
  306.     if (baudrate() <= 1200)
  307.         incmove = 4;
  308.     if (baudrate() <= 300)
  309.         incmove = 8;
  310.     for (i = MAXROW ; i >= y; i -= incmove) {    /* from the screen bottom to word */
  311.         if (i < MAXROW)        /* restore previous position */
  312.             mvaddch(i + incmove,x,oldc);
  313.         oldc = mvinch(i,x);    /* store old char for restore */
  314.         mvaddch(i,x,missile);    /* put out 'missile' */
  315.         refresh();
  316.         if (baudrate() > 9600)
  317.             napms (100);    /* if REAL fast, slow it down */
  318.     }
  319.     if (oldc)
  320.         mvaddch(i + incmove,x,oldc);    /* clear last 'missile' */
  321.     if (((total % addtarget) == 0 ) && ((targets + 1) < MAXTARGET))
  322.         newtarget(targets++);
  323.     if (((total % movedown) == 0 ) && (highrow > (lowrow + 1)) )
  324.         lowrow++;
  325.     if (((total % movebottom) == 0 ) && (highrow < (MAXROW - 2)) )
  326.         highrow++;
  327.     showscore();
  328.     cleartarget(num);
  329.     newtarget(num);
  330. }
  331.  
  332. /* CLEARTARGET
  333.  *
  334.  * Make an explosion where the word was if baudrate allows, and clear
  335.  * the screen at the word location
  336.  */
  337. void
  338. cleartarget(num)
  339. int num;
  340. {
  341. register int i;
  342. int j;
  343. char c;
  344. #ifdef MSDOS
  345.   char    explode[]={ '*', '#', 0xDB, 0xB2, 0xB1, 0xB0, ' '};
  346.   int    jmax = 7;        /* number of symbols in explosion */
  347.   int    naptime = 70;        /* 500 msec / 7 symbols ~= 70 msec */
  348. #else
  349.   char    explode[]={ '*', '#', ' '};
  350.   int    jmax = 3;        /* number of symbols in explosion */
  351.   int    naptime = 160;        /* 500 msec / 3 symbols ~= 160 msec */
  352. #endif
  353.  
  354.     for (j = 0; j < jmax; j++) {
  355.         if ((j < jmax) && (baudrate() < 4800))
  356.             continue;
  357.         c = explode [j];
  358.         move(target[num].row,target[num].col);
  359.         for (i=0;i< target[num].len; i++) {
  360.             addch(c);
  361.         }
  362.         refresh();
  363.         if (baudrate() > 9600)
  364.             napms (naptime);/* if REAL fast, slow it down */
  365.     }
  366. }
  367.  
  368. /* SHOWSCORE
  369.  *
  370.  * Show the total words gotten and words missed
  371.  */
  372. void
  373. showscore()
  374. {
  375.     mvprintw(2,30,"Hits: %d",total);
  376.     mvprintw(2,42,"Misses: %d",missed);
  377. }
  378.  
  379. /* SCREENINIT
  380.  *
  381.  * Initialize the screen for the game
  382.  */
  383. void
  384. screeninit()
  385. {
  386.     clear();
  387.         srand(time(0));    /* set up random numbers */
  388.     standout();
  389.     mvprintw(1,35,"**TYPEFAST**");
  390.     mvprintw(MAXROW,1,"<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>");
  391.     standend();
  392.     showscore();
  393.     refresh();
  394. }
  395.  
  396. /* WPM
  397.  *
  398.  * Calculate total wpm by taking the number of key strokes passed,
  399.  * calculating elapsed time, and figuring 5 chars per word.
  400.  */
  401. int
  402. wpm(tstrokes)
  403. long tstrokes;
  404. {
  405. long totaltime;
  406. float result;
  407. int iresult;
  408.     totaltime = time((long *) 0);
  409.     totaltime -= starttime;    /* figure total time in seconds */
  410.     if (totaltime < 1)
  411.         return(0);
  412.     result = (tstrokes * 60.0)/ (5.0 * totaltime);
  413.     iresult = (int) result;
  414.     return(iresult);
  415. }
  416.  
  417. /* GETSETUP
  418.  *
  419.  * This routine sets up the initial screen and gives instructions,
  420.  * and prompts for game level.  It then sets several game variables
  421.  * for number of targets, locations, and how often variables are
  422.  * changed to increase difficulty.
  423.  */
  424. void
  425. getsetup()
  426. {
  427. char c;
  428.     clear();
  429.     standout();
  430.     mvprintw(0,0,"<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>");
  431.     mvprintw(MAXROW-1,0,"<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>");
  432.     mvprintw(5,30,"The TYPEFAST Game");
  433.     standend();
  434.     mvprintw(12,10,"Do you need instructions?  Press y or n (no RETURN)");
  435.     refresh();
  436.     while (((c = getch()) != 'y') && (c != 'n')) ;
  437.     move(12,10);
  438.     clrtoeol();
  439.     if (c == 'y') {
  440.         move(8,0);
  441.         printw("Words will move down the screen toward the bottom.  You must type\n");
  442.         printw("each word before it reaches the bottom.  End each word you type with\n");
  443.         printw("a SPACE or a RETURN.  When you successfully type a word in time a\n");
  444.         printw("new one will take its place somewhere on the screen.  The number\n");
  445.         printw("of words will increase as you go along and the words will get closer\n");
  446.         printw("to the bottom of the screen.  At the end your Words Per Minute is shown.\n");
  447.     }
  448.     standout();
  449.     mvprintw(16,10,"Press the letter of the level of difficult you wish (no RETURN)");
  450.     standend();
  451.     mvprintw(18,33,"1-Easy");
  452.     mvprintw(19,33,"2-Normal");
  453.     mvprintw(20,33,"3-Hard");
  454.     mvprintw(21,33,"q-Quit");
  455.     refresh();
  456.     while (1) {
  457.         c = getch();
  458.         if ((c >= '1') && (c <= '3'))
  459.             break;
  460.         if (c == 'q')
  461.             error("Game aborted as requested");
  462.     }
  463.     switch (c) {
  464.      case '1':
  465.         addtarget=  60;    /*Add a new target every x hits*/
  466.         movedown=   50;    /*move top row down every x hits */
  467.         movebottom=130;    /*move botom row down every x hits */
  468.         startwords=  2;    /*Starting target words*/
  469.         lowrow =     4;    /* lowest row number for a word */
  470.         highrow =   15;    /* highest row number for a word */
  471.         break;
  472.      case '2':
  473.         addtarget=  50;    /*Add a new target every x hits*/
  474.         movedown=   50;    /*move top row down every x hits */
  475.         movebottom=100;    /*move botom row down every x hits */
  476.         startwords=  3;    /*Starting target words*/
  477.         lowrow =     6;    /* lowest row number for a word */
  478.         highrow =   17;    /* highest row number for a word */
  479.         break;
  480.      case '3':
  481.         addtarget=  50;    /*Add a new target every x hits*/
  482.         movedown=   30;    /*move top row down every x hits */
  483.         movebottom= 60;    /*move botom row down every x hits */
  484.         startwords=  5;    /*Starting target words*/
  485.         lowrow =    10;    /* lowest row number for a word */
  486.         highrow =   18;    /* highest row number for a word */
  487.         break;
  488.      default:
  489.         error("Internal game switch error");
  490.     }
  491.     clear();
  492. }
  493.